home *** CD-ROM | disk | FTP | other *** search
- ⓪ IMPLEMENTATION MODULE FileManagement;⓪ (*$R-,Y+*)⓪ (*$H+*)⓪ ⓪ (*FROM InOut IMPORT WriteString, WriteLn, Read, WriteCard, WriteInt;*)⓪ ⓪ ⓪ (* --------------------------------------------------------------------------⓪!* System-Version: MOS 1.1⓪!* --------------------------------------------------------------------------⓪!* Version : 1.01⓪!* --------------------------------------------------------------------------⓪!* Text-Version : V#0262⓪!* --------------------------------------------------------------------------⓪!* Modul-Holder : Manuel Chakravarty⓪!* --------------------------------------------------------------------------⓪!* Copyright August 1988 by Manuel Chakravarty⓪!* Vertriebsrechte für ATARI ST unter MEGAMAX Modula-2⓪!* liegen bei Application Systems Heidelberg⓪!* --------------------------------------------------------------------------⓪!* MCH : Manuel Chakravarty⓪!* DS : Dirk Steins ⓪!* --------------------------------------------------------------------------⓪!* Datum Autor Version Bemerkung (Arbeitsbericht)⓪!*⓪!* 07.08.88 MCH V0.01 Erste Definitionen⓪!* 08.08.88 MCH V0.01 'fileList' + 'insertFileInList'⓪!* 09.08.88 MCH V0.01 Austesten der 'fileList'-Verwaltung + 'DeleteFiles'⓪!* 09.08.88 MCH V0.02 Nochmal⓪!* 10.08.88 MCH V0.02 'FormatDisk' (norm. SS und DS) + 'DeleteFiles'⓪!* 11.08.88 MCH V0.02 'CopyFiles' läuft (Tra-Ra!)⓪!* 24.08.88 MCH V0.03 'CountFilesAndDirs' extern⓪!* 25.08.88 MCH V0.03 Geänderte Status-Verwaltung⓪!* 27.08.88 MCH V0.03 'minExternalSpace' eingeführt.⓪!* 28.08.88 MCH V0.04 'FileInformation' Def. + Imp.⓪!* 11.08.88 MCH V0.04 Datum/Uhrzeit bleibt beim Kopieren erhalten⓪!* 03.09.89 MCH V0.04 Fehlerbehandlung verbessert⓪!* 11.09.89 TT V0.05 readIntoBuffer: Fehlerabfrage entfernt⓪!* 30.6.90 DS V0.06 DestPath von Files wird bei geändertem Ordnername⓪!* jetzt korrekt geändert. Änderungen sind gekenn-⓪!* zeichnet mit %%.⓪!* 24.10.90 TT V0.07 Doku im Def-Text korrigiert; FormatDrive mit⓪!* mit Directory.Drive-Werten definiert (Def-Text);⓪!* $H+ eingebaut⓪!* 10.11.90 TT V0.07 $R-⓪!* 11.03.91 TT V1.01 FileInformation berücksichtigt Ordner und kann⓪!* auch Zeit/Datum neu setzen.⓪!* 09.04.91 TT V1.02 FormatDisk wertet 'drive' nun richtig aus (bisher⓪!* wurde bei 'drvA' LW B: formatiert.⓪!* --------------------------------------------------------------------------⓪!* Modul-Beschreibung:⓪!*⓪!* Dieses Modul stellt Routinen für die Dateiverwaltung zur Verfügung.⓪!* --------------------------------------------------------------------------⓪!*)⓪ ⓪ (* -- Wie sieht es mit Datum und Zeit bei Ordnern aus??????⓪!* -- Wird beim Namenskonflikt von Ordnern ein neuer Name angegeben, so muß⓪!* der DestPath der Ordnerelemente entsprechend geändert werden.⓪!* Behoben Dirk Steins⓪!* -- Tritt bei 'flushBufferElem' während des Schreibens ein Fehler auf, so⓪!* ist nicht gewährleistet, daß das File anständig geschlossen wird.⓪!* -- Evtl. 'queryFileList' exportieren (z.B für Modul-Loading in der Shell).⓪!*)⓪ ⓪ ⓪ FROM SYSTEM IMPORT ADDRESS, TSIZE,⓪3ASSEMBLER, ADR;⓪ ⓪ FROM Storage IMPORT ALLOCATE, DEALLOCATE, MemAvail;⓪ ⓪ FROM Strings IMPORT Length, Concat, Append, Empty, Insert, Copy, StrEqual,⓪4Assign;⓪ ⓪ IMPORT Strings, FastStrings, FuncStrings;⓪ ⓪ FROM MOSGlobals IMPORT OutOfMemory, GeneralErr, fOK, fFileNotFound,⓪7fPathNotFound, fAccessDenied, fFileExists,⓪7fDiskFull, fIllegalCall, DriveStr, PathStr,⓪7FileStr;⓪ ⓪ FROM Clock IMPORT Time, Date;⓪ ⓪ FROM Directory IMPORT FileAttr, FileAttrSet, DirEntry,⓪6SetFileAttr, Delete, Rename, GetDirEntry,⓪6DirQuery, CreateDir, DeleteDir;⓪ ⓪ FROM FileNames IMPORT SplitPath;⓪ ⓪ FROM Files IMPORT File, Access, ReplaceMode,⓪2Create, Open, Close, SetDateTime, GetDateTime, State,⓪2GetStateMsg, ResetState, Remove;⓪ ⓪ FROM Binary IMPORT SeekMode,⓪3ReadBytes, WriteBytes, FileSize, Seek, FilePos;⓪ ⓪ FROM Lists IMPORT List, CreateList, DeleteList, RemoveEntry, AppendEntry,⓪2ResetList, NextEntry, PrevEntry, CurrentEntry, NoOfEntries;⓪ ⓪ FROM SysUtil0 IMPORT VarEqual;⓪ ⓪ ⓪ CONST (* MOS const.s *)⓪ ⓪(noErrorTrap = 6;⓪ ⓪((* system call opcodes *)⓪ ⓪(flopwr = 9;⓪(flopfmt = 10;⓪(protobt = 18;⓪(⓪(xbios = 14;⓪(⓪((* misc *)⓪(⓪(filesAndSubdirs = FileAttrSet {subdirAttr};⓪(⓪(⓪(minCopySpace = 10L * 1024L; (* 10k minimal *)⓪(minExternalSpace= 30L * 1024L; (* 30k minimal for other prog.s *)⓪((* erweitert auf 30k für Pfadlisten *)⓪ ⓪ TYPE ptrMaxStr = POINTER TO ARRAY[0..32767] OF CHAR;⓪(str128 = ARRAY[0..127] OF CHAR;⓪(fileName = ARRAY[0..11] OF CHAR;⓪(ptrCardinal = POINTER TO CARDINAL;⓪(⓪(⓪ TYPE statusRecord = RECORD⓪<fileErrAlert: FileErrorAlertProc;⓪<⓪<showStatus : FileOpStatusProc;⓪<noFiles : CARDINAL;⓪:END;⓪(ptrStatusRecord = POINTER TO statusRecord;⓪(⓪((* types for the copy buffer *)⓪(⓪(copyBufferElem = POINTER TO RECORD⓪<next : copyBufferElem; (* NIL <=> not used *)⓪<newPath : str128;⓪<isSubdir: BOOLEAN;⓪<date : Date; (* of creation *)⓪<time : Time; (* of creation *)⓪<seekPos : LONGCARD; (* append if > 0L *)⓪<start : ADDRESS; (* start of data *)⓪<length : LONGCARD; (* length of data *)⓪:END;⓪(⓪(copyBuffer = POINTER TO RECORD⓪<bottom, (* first buffer elem *)⓪<next : copyBufferElem; (* next elem. to use *)⓪<length : LONGCARD; (* buffer length *)⓪<⓪<status : statusRecord;⓪<⓪<feAlert : FileExistsAlertProc;⓪<oldPathLen: CARDINAL;⓪<newPath : str128;⓪<⓪<success : BOOLEAN; (* FALSE ~ Error *)⓪:END;⓪'⓪ ⓪ VAR voidO : BOOLEAN;⓪(voidI : INTEGER;⓪(voidFN: fileName;⓪(void128: str128;⓪(⓪ ⓪ CONST DebugInfo = FALSE;⓪ ⓪ (*$? DebugInfo:⓪ ⓪ PROCEDURE wLn (REF str: ARRAY OF CHAR);⓪ ⓪"BEGIN⓪$WriteString (str); WriteLn;⓪"END wLn;⓪ ⓪ PROCEDURE w (REF str: ARRAY OF CHAR);⓪ ⓪"BEGIN⓪$WriteString (str);⓪"END w;⓪ ⓪ PROCEDURE wc (c: LONGCARD);⓪ ⓪"BEGIN⓪$WriteCard (c, 6);⓪"END wc;⓪ ⓪ PROCEDURE wi (c: INTEGER);⓪ ⓪"BEGIN⓪$WriteInt (c, 6);⓪"END wi;⓪ ⓪ PROCEDURE wsiLn (REF str: ARRAY OF CHAR; i: INTEGER);⓪ ⓪"BEGIN⓪$w (str); wi (i); WriteLn;⓪"END wsiLn;⓪ ⓪ PROCEDURE wcsLn (l: LONGCARD; REF str: ARRAY OF CHAR);⓪ ⓪"BEGIN⓪$wc (l); wLn (str);⓪"END wcsLn;⓪"⓪ PROCEDURE wscLn (REF str: ARRAY OF CHAR; l: LONGCARD);⓪ ⓪"BEGIN⓪$w (str); wc (l); WriteLn;⓪"END wscLn;⓪"⓪ PROCEDURE Wait;⓪ ⓪"VAR ch: CHAR;⓪"⓪"BEGIN⓪$Read (ch);⓪"END Wait;⓪!*)⓪"⓪8(* misc. proc.s *)⓪8(* ============ *)⓪ ⓪ PROCEDURE reportOutOfMemory;⓪ ⓪"(*$L-*)⓪"BEGIN⓪$ASSEMBLER⓪(TRAP #noErrorTrap⓪(DC.W OutOfMemory - $4000⓪$END;⓪"END reportOutOfMemory;⓪"(*$L=*)⓪"⓪ PROCEDURE reportPathFault;⓪ ⓪"(*$L-*)⓪"BEGIN⓪$ASSEMBLER⓪(TRAP #noErrorTrap⓪(DC.W GeneralErr - $C000⓪(ACZ 'FileManagement: Illegal path!'⓪(SYNC⓪$END;⓪"END reportPathFault;⓪"(*$L=*)⓪"⓪ ⓪ PROCEDURE isSubdir (attrs: FileAttrSet): BOOLEAN;⓪ ⓪"BEGIN⓪$RETURN subdirAttr IN attrs⓪"END isSubdir;⓪ ⓪ ⓪ PROCEDURE GetFileAttr (REF name : ARRAY OF CHAR;⓪7VAR attr : FileAttrSet;⓪7VAR result: INTEGER);⓪"⓪"VAR entry: DirEntry;⓪"⓪"BEGIN⓪$GetDirEntry (name, entry, result);⓪&(* -> Directory.GetFileAttr geht nicht bei Subdirs. *)⓪$attr := entry.attr;⓪"END GetFileAttr;⓪ ⓪ PROCEDURE doShowStatus ( statusRecPtr: ptrStatusRecord;⓪<ioRes : INTEGER;⓪8VAR stop : BOOLEAN);⓪ ⓪"VAR report,⓪(continue: BOOLEAN;⓪(⓪"BEGIN⓪$WITH statusRecPtr^ DO⓪$⓪&report := (ioRes = fFileNotFound) OR (ioRes = fPathNotFound)⓪0OR (ioRes = fAccessDenied) OR (ioRes = fDiskFull);⓪&continue := (ioRes = fOK) OR (ioRes = fFileNotFound)⓪2OR (ioRes = fPathNotFound) OR (ioRes = fAccessDenied)⓪2OR (ioRes = fFileExists);⓪$⓪&IF report THEN fileErrAlert (ioRes) END;⓪&stop := ~ continue;⓪$⓪&IF ~ stop THEN⓪(IF noFiles > 0 THEN DEC (noFiles) END;⓪(showStatus (noFiles, stop);⓪&END;⓪&⓪$END;⓪"END doShowStatus;⓪ ⓪ ⓪0(* operations on the 'copyBuffer' *)⓪0(* ============================== *)⓪0⓪ ⓪ (* createCopyBuffer -- Alloc.s as much memory as possible and creates⓪!* a 'copyBuffer' with it.⓪!* 'useAllMem = FALSE' means to use 2/5 of the largest⓪!* avaible mem. block, else the whole block is used.⓪!* 'success = FALSE' means, not enough memory.⓪!*)⓪!⓪ PROCEDURE createCopyBuffer (VAR cb : copyBuffer;⓪@useAllMem: BOOLEAN;⓪<VAR success : BOOLEAN);⓪ ⓪"PROCEDURE memAvail (): LONGCARD;⓪"⓪$VAR res: LONGCARD;⓪"⓪$BEGIN⓪&IF useAllMem THEN⓪(res := MemAvail ();⓪(IF res < minExternalSpace THEN res := 0⓪(ELSE res := res - minExternalSpace END;⓪&ELSE⓪(res := MemAvail () * 2L DIV 5L;⓪(IF res < minExternalSpace THEN res := 0 END;⓪&END;⓪&⓪&res := res - res MOD 2L; (* make even *)⓪&⓪&RETURN res⓪$END memAvail;⓪$⓪ ⓪"BEGIN⓪$success := (memAvail () >= minCopySpace );⓪$IF ~ success THEN RETURN END;⓪$⓪$NEW (cb);⓪$WITH cb^ DO⓪&length := memAvail (); (* take as much as possible *)⓪&ALLOCATE (bottom, length);⓪&next := bottom; (* next elem. to use is the first elem. *)⓪&bottom^.next := NIL; (* first elem. is not yet in use *)⓪$END;⓪"END createCopyBuffer;⓪ ⓪ PROCEDURE deleteCopyBuffer (cb: copyBuffer);⓪ ⓪"BEGIN⓪$DEALLOCATE (cb^.bottom, 0L);⓪$DISPOSE (cb);⓪"END deleteCopyBuffer;⓪"⓪ ⓪ (* bufAvail -- Determines the maximum amount of bytes, that are avaible⓪!* in the 'cb'.⓪!*)⓪ ⓪ PROCEDURE bufAvail (cb: copyBuffer): LONGCARD;⓪ ⓪"BEGIN⓪$RETURN cb^.length - (LONGCARD (cb^.next) - LONGCARD (cb^.bottom))⓪+- SIZE (cb^.next^)⓪"END bufAvail;⓪"⓪ (* flushCopyBuffer -- Writes the data in 'cb' to the destination.⓪!*)⓪ ⓪((* %% added 27.6.90 DS *)⓪((* pc: short for PathChange *)⓪ (* The 'pcList' is the pathChangedList. In this list all path's⓪!* which were changed during flushBuffer will be stored. ⓪!* This Types and vars are global because the 'pcList' is initialised in⓪!* the procedure 'copyFiles'. And it has to be global because otherwise⓪!* some entries would be forgotten.⓪!*)⓪!⓪"TYPE pcEntry = RECORD⓪>oldPath,⓪>newPath : str128;⓪<END;⓪*pcPtr = POINTER TO pcEntry;⓪*⓪"VAR pcList : List;⓪ ⓪ PROCEDURE flushCopyBuffer (cb: copyBuffer);⓪ ⓪"VAR elem : copyBufferElem;⓪(ioRes: INTEGER;⓪(f : File;⓪(mode : ReplaceMode;⓪(path : str128;⓪(fn,⓪(orgFn, (* %% added 30.6.90 DS: is needed for the⓪A* pcList and the original pathname in it.⓪A*)⓪(oldFn: fileName;⓪(stop : BOOLEAN;⓪(⓪"PROCEDURE stateErr (): BOOLEAN;⓪$⓪$BEGIN⓪&ioRes := State (f);⓪&IF ioRes # fOK THEN ResetState (f) END;⓪&RETURN ioRes # fOK⓪$END stateErr;⓪$⓪((* %% added 27.6.90 DS *)⓪"PROCEDURE insertChangeEntry (VAR path : ARRAY OF CHAR;⓪?VAR old, new : ARRAY OF CHAR;⓪?start : CARDINAL) : BOOLEAN;⓪$(* inserts the newPath corresponding to oldPath in the ⓪%* pathList. If no oldPath is found a new entry is created.⓪%* Creating a new entry is the normal case due to changes in⓪%* development.⓪%*)⓪$VAR sPath : str128;⓪(pc : pcPtr;⓪"BEGIN⓪$FastStrings.Concat (path, old, sPath);⓪$ResetList (pcList);⓪$REPEAT ⓪&pc := NextEntry (pcList);⓪$UNTIL (pc = NIL) OR StrEqual (sPath, pc^.oldPath);⓪$IF pc # NIL⓪$THEN⓪&FastStrings.Concat (path, new, sPath);⓪&FastStrings.Assign (sPath, pc^.newPath);⓪$ELSE⓪&ALLOCATE (pc, TSIZE (pcEntry));⓪&IF pc = NIL THEN reportOutOfMemory; RETURN FALSE END;⓪&FastStrings.Concat (path, old, pc^.oldPath);⓪&FastStrings.Concat (path, new, pc^.newPath);⓪&AppendEntry (pcList, pc, voidO);⓪&IF voidO THEN reportOutOfMemory; RETURN FALSE END;⓪$END;⓪$RETURN TRUE⓪"END insertChangeEntry;⓪"⓪"(* %% added 27.6.90 DS *)⓪"PROCEDURE TestAndChange (VAR path : ARRAY OF CHAR;⓪;last : CARDINAL);⓪"(* If path is in the pcList, path will be replaced by the newPath.⓪#* this proc call's itself recursively to change previous changed ⓪#* parts of a path correct.⓪#* 'last' is a control-parameter to pretend infinite loops. (i don't ⓪#* know if it's necessary).⓪#*)⓪%VAR p : INTEGER;⓪)l : CARDINAL;⓪)pc: pcPtr;⓪)tPath : str128;⓪)tName : fileName;⓪"BEGIN⓪$l := Length (path);⓪$IF (l > 2) AND ~(l = last)⓪$THEN⓪&SplitPath (path, tPath, tName);⓪&tPath[Length(tPath)-1] := 0c; (* '\' löschen *)⓪&TestAndChange (tPath, l);⓪&Append ('\',tPath, voidO); (* '\' wieder anfügen *)⓪&FastStrings.Concat (tPath, tName, path);⓪&ResetList (pcList);⓪&REPEAT⓪(pc := NextEntry (pcList);⓪&UNTIL (pc = NIL) OR StrEqual (path, pc^.oldPath);⓪&IF pc # NIL⓪&THEN⓪(FastStrings.Assign (pc^.newPath, path);⓪&END;⓪$END;⓪"END TestAndChange;⓪"⓪"PROCEDURE flushOneElem;⓪"⓪$VAR pathChanged : BOOLEAN;⓪"⓪$BEGIN⓪&WITH elem^ DO IF isSubdir THEN⓪&⓪((* %% added by DS 27.6.90: *)⓪(SplitPath (newPath, path, orgFn);⓪(TestAndChange (path, 0);⓪(FastStrings.Concat (path, orgFn, newPath);⓪*⓪(pathChanged := FALSE;⓪(⓪(LOOP⓪*CreateDir (newPath, ioRes);⓪*IF ioRes = fAccessDenied THEN (* folder exists *)⓪*⓪,SplitPath (newPath, path, oldFn);⓪,fn := oldFn;⓪,IF ~ cb^.feAlert (fn) THEN ioRes := fFileExists; EXIT END;⓪,⓪,(* %% added by DS 27.6.90: *)⓪,IF ~StrEqual (oldFn, fn)⓪,THEN ⓪.pathChanged := TRUE⓪,ELSE⓪.ioRes := fFileExists;⓪.EXIT⓪,END;⓪,⓪,FastStrings.Concat (path, fn, newPath);⓪,⓪*ELSE EXIT END; (* success *)⓪(END;⓪(⓪((* %% added by DS 27.6.90: *)⓪(IF pathChanged THEN⓪+IF ~insertChangeEntry (path, orgFn, fn, cb^.oldPathLen)⓪+THEN stop := TRUE⓪+END;⓪(END;⓪(⓪&ELSE⓪&⓪(IF seekPos > 0L THEN (* append *)⓪(⓪*Open (f, newPath, writeOnly);⓪*IF stateErr () THEN Remove (f); RETURN END;⓪*Seek (f, seekPos, fromBegin);⓪*IF stateErr () THEN Remove (f); RETURN END;⓪*⓪(ELSE (* new file *)⓪*mode := noReplace;⓪*⓪*TestAndChange (newPath, 0);⓪*⓪*LOOP⓪*⓪,Create (f, newPath, writeOnly, mode);⓪,IF State (f) = fFileExists THEN (* file exists *)⓪,⓪.ResetState (f);⓪.SplitPath (newPath, path, oldFn);⓪.fn := oldFn;⓪.IF ~ cb^.feAlert (fn) THEN ioRes := fFileExists; RETURN END;⓪.IF StrEqual (fn, oldFn) THEN mode := replaceOld⓪.ELSE FastStrings.Concat (path, fn, newPath) END;⓪.⓪,ELSIF stateErr () THEN RETURN (* file error! *)⓪,ELSE EXIT END; (* success *)⓪,⓪*END;⓪*⓪(END;⓪(⓪(WriteBytes (f, start, length);⓪(IF stateErr () THEN Remove (f); RETURN END;⓪(Close (f);⓪(Open (f, newPath, writeOnly);⓪(SetDateTime (f, date, time);⓪((* IF stateErr () THEN Remove (f); RETURN END; *)⓪(Close (f);⓪(⓪&END END;⓪$END flushOneElem;⓪$⓪"BEGIN⓪$elem := cb^.bottom;⓪$LOOP⓪&IF elem^.next = NIL THEN EXIT END;⓪&⓪&flushOneElem;⓪&⓪&doShowStatus (ADR (cb^.status), ioRes, stop); (* communicate *)⓪&IF stop THEN cb^.success := FALSE; EXIT END;⓪&⓪&elem := elem^.next;⓪$END;⓪$⓪$cb^.next := cb^.bottom; (* free buffer contens *)⓪$cb^.next^.next := NIL;⓪"END flushCopyBuffer;⓪"⓪ ⓪ (* createCopyBufferElem -- Creates a new elem. in the 'copyBuffer', if⓪!* there is not enough room to do so, the buffer⓪!* is flushed first.⓪!* Call only, if there are no open files.⓪!*)⓪ ⓪ PROCEDURE createCopyBufferElem ( cb : copyBuffer;⓪@VAR elem: copyBufferElem);⓪ ⓪"BEGIN⓪$IF bufAvail (cb) < (minCopySpace DIV 2L) THEN⓪&flushCopyBuffer (cb); IF ~ cb^.success THEN RETURN END;⓪$END;⓪$⓪$WITH cb^ DO⓪&elem := next;⓪&next := copyBufferElem (LONGCARD (bottom) + length - SIZE (cb^.next^));⓪&elem^.next := next;⓪&elem^.next^.next := NIL; (* mark next elem as free *)⓪&elem^.start := ADDRESS (elem) + ADDRESS (SIZE (elem^));⓪&elem^.length := LONGCARD (elem^.next) - LONGCARD (elem^.start);⓪$END;⓪"END createCopyBufferElem;⓪ ⓪ (* deleteCopyBufferElem -- Deletes a 'copyBufferElem'. The element must⓪!* be the last in the 'copyBuffer'!⓪!*)⓪ ⓪ PROCEDURE deleteCopyBufferElem ( cb: copyBuffer;⓪@VAR elem: copyBufferElem);⓪ ⓪"BEGIN⓪$cb^.next := elem;⓪$elem^.next := NIL;⓪"END deleteCopyBufferElem;⓪"⓪ (* shrinkBufferElem -- Reduces the length of 'elem' to 'bytes' byte.⓪!*⓪!* ATTENTION: -- Could only be used for the last⓪!* used element of a buffer.⓪!* -- Length of the elem. and start of⓪!* the next differ, if 'bytes' is odd.⓪!*)⓪ ⓪ PROCEDURE shrinkBufferElem (cb : copyBuffer;⓪<elem : copyBufferElem;⓪<bytes: LONGCARD);⓪ ⓪"BEGIN⓪$(* if not last used elem. or trying to enlarge elem. size⓪%*)⓪$IF (elem^.next^.next # NIL) OR (elem^.length < bytes) THEN HALT END;⓪$⓪$elem^.length := bytes;⓪$elem^.next := ADDRESS (elem^.start) + ADDRESS (bytes + bytes MOD 2L);⓪$elem^.next^.next := NIL;⓪$cb^.next := elem^.next;⓪"END shrinkBufferElem;⓪"⓪"⓪ PROCEDURE readIntoBuffer (REF path: ARRAY OF CHAR;⓪:VAR pos : LONGCARD;⓪>cb : copyBuffer);⓪ ⓪"VAR f : File;⓪(bufElem : copyBufferElem;⓪(readBytes: LONGCARD;⓪(success : BOOLEAN;⓪"⓪"PROCEDURE stateErr (): BOOLEAN;⓪"⓪$BEGIN⓪&cb^.success := (State (f) = fOK);⓪&IF ~ cb^.success THEN⓪(cb^.status.fileErrAlert (State (f));⓪(ResetState (f);⓪(pos := 0L;⓪(Close (f);⓪(bufElem^.next := NIL;⓪&END;⓪&RETURN ~ cb^.success⓪$END stateErr;⓪$⓪ ⓪"BEGIN⓪$⓪$(* alloc. room in the buffer for the new file (or part of it).⓪%*)⓪%⓪$createCopyBufferElem (cb, bufElem);⓪$IF ~ cb^.success THEN⓪$pos := 0L; RETURN END;⓪$WITH bufElem^ DO⓪&Copy (path, cb^.oldPathLen, Length (path) - cb^.oldPathLen, newPath,⓪,voidO);⓪&Insert (cb^.newPath, 0, newPath, success);⓪&IF ~ success THEN⓪(reportPathFault;⓪(deleteCopyBufferElem (cb, bufElem);⓪(pos := 0L;⓪(RETURN⓪&END;⓪&isSubdir := FALSE;⓪&seekPos := pos;⓪&⓪&Open (f, path, readOnly); IF stateErr () THEN RETURN END;⓪&GetDateTime (f, date, time);⓪&Seek (f, pos, fromBegin); IF stateErr () THEN RETURN END;⓪&ReadBytes (f, start, length, readBytes); IF stateErr () THEN RETURN END;⓪&pos := FilePos (f);⓪&IF pos = FileSize (f) THEN pos := 0L END; (* EOF *)⓪&Close (f);⓪&⓪&shrinkBufferElem (cb, bufElem, readBytes);⓪&⓪$END;⓪"END readIntoBuffer;⓪ ⓪"⓪0(* proc.s for query through file list *)⓪0(* ================================== *)⓪0⓪0⓪((* The following proc.s shouldn't directly or indirectly be⓪)* recursive. Cause the caller is working with global var.s⓪)*)⓪)⓪ TYPE fileHandleProc = PROCEDURE (REF (*file: *) ARRAY OF CHAR,⓪I(*env : *) ADDRESS): BOOLEAN;⓪(dirHandleProc = PROCEDURE (REF (*dir: *) ARRAY OF CHAR,⓪I(*env: *) ADDRESS): BOOLEAN;⓪I⓪(oldPathLenToEnvProc = PROCEDURE ((*oldLen: *) CARDINAL,⓪I(*env : *) ADDRESS);⓪I⓪(queryEnv = RECORD⓪<handleFile: fileHandleProc;⓪<handleDir : dirHandleProc;⓪<handleEnv : ADDRESS;⓪<dirFirst : BOOLEAN;⓪<⓪<stop : BOOLEAN;⓪<pathChanged : BOOLEAN;⓪<newPath : PathStr;⓪:END;⓪ ⓪ VAR dontKnowANameEnv: queryEnv;⓪(dontKnowANameStr: str128;⓪(⓪(⓪ ⓪ PROCEDURE dontKnowAName (REF path: ARRAY OF CHAR; entry: DirEntry): BOOLEAN;⓪ ⓪"VAR success: BOOLEAN;⓪(ioRes : INTEGER;⓪((* %% added 30.6.90 DS: because dontKnowAName calls itself recursively⓪)* the following var has to be local. Otherwise some pathes will⓪)* not be set correct! See remark 34 lines above!!⓪)*)⓪(dontKnowANameStr: str128;⓪ ⓪"BEGIN⓪$IF entry.name[0] # '.' THEN WITH dontKnowANameEnv DO⓪$⓪&Concat (path, entry.name, dontKnowANameStr, success);⓪&IF ~ success THEN reportPathFault; stop := TRUE; RETURN FALSE END;⓪&IF isSubdir (entry.attr) THEN⓪&⓪(IF dirFirst THEN⓪*stop := ~ handleDir (dontKnowANameStr, handleEnv);⓪*IF stop THEN RETURN FALSE END;⓪(END;⓪(⓪(Append ('\*.*', dontKnowANameStr, success);⓪(IF ~ success THEN reportPathFault; stop := TRUE; RETURN FALSE END;⓪(DirQuery (dontKnowANameStr, filesAndSubdirs, dontKnowAName, ioRes);⓪(IF stop OR (ioRes # fOK) THEN stop := TRUE; RETURN FALSE END;⓪(⓪(IF ~ dirFirst THEN⓪*Concat (path, entry.name, dontKnowANameStr, success);⓪*stop := ~ handleDir (dontKnowANameStr, handleEnv);⓪*IF stop THEN RETURN FALSE END;⓪(END;⓪(⓪&ELSE stop := ~ handleFile (dontKnowANameStr, handleEnv) END;⓪&⓪&IF stop THEN RETURN FALSE END;⓪&⓪$END END;⓪$⓪$RETURN TRUE⓪"END dontKnowAName;⓪ ⓪ PROCEDURE queryFileList (REF path : ARRAY OF CHAR;⓪=files : List;⓪=workOnFile : fileHandleProc;⓪=workOnDir : dirHandleProc;⓪=setOldPathLen : oldPathLenToEnvProc;⓪=workEnv : ADDRESS;⓪=workOnDirFirst: BOOLEAN);⓪ ⓪"VAR entry : ptrMaxStr;⓪(str,⓪(str2,⓪(str3 : str128;⓪(ioRes : INTEGER;⓪(attrs : FileAttrSet;⓪(success: BOOLEAN;⓪ ⓪"BEGIN⓪$WITH dontKnowANameEnv DO⓪$⓪&handleFile := workOnFile;⓪&handleDir := workOnDir;⓪&handleEnv := workEnv;⓪&dirFirst := workOnDirFirst;⓪&stop := FALSE;⓪&pathChanged := FALSE;⓪&⓪&IF path[0]#0C THEN⓪(IF path [Length (path) - 1] = '\' THEN FastStrings.Assign (path, str3)⓪(ELSE Concat (path, '\', str3, success) END;⓪&ELSE str3 := '' END;⓪&⓪&ResetList (files);⓪&entry := NextEntry (files);⓪&WHILE entry # NIL DO⓪&⓪(FastStrings.Assign (entry^, str2); (* !!! 'entry^' by reference !!! *)⓪(⓪(Concat (str3, str2, str, success);⓪(IF ~ success THEN reportPathFault; RETURN END;⓪(⓪(SplitPath (str, str2, voidFN);⓪(setOldPathLen (Length (str2), workEnv);⓪(⓪(GetFileAttr (str, attrs, ioRes); IF ioRes # fOK THEN RETURN END;⓪(IF isSubdir (attrs) THEN⓪(⓪*IF dirFirst THEN⓪,IF ~ handleDir (str, handleEnv) THEN RETURN END⓪*END;⓪*⓪*Concat (str, '\*.*', str2, success);⓪*IF ~ success THEN reportPathFault; RETURN END;⓪*DirQuery (str2, filesAndSubdirs, dontKnowAName, ioRes);⓪*IF stop OR (ioRes # fOK) THEN RETURN END;⓪(⓪*IF ~ dirFirst THEN⓪,IF ~ handleDir (str, handleEnv) THEN RETURN END⓪*END;⓪*⓪(ELSE IF ~ handleFile (str, handleEnv) THEN RETURN END END;⓪(⓪(entry := NextEntry (files);⓪&END;⓪&⓪$END;⓪"END queryFileList;⓪!⓪!⓪ PROCEDURE statusDummy (c: CARDINAL; VAR s: BOOLEAN);⓪ ⓪"BEGIN⓪$s := FALSE;⓪"END statusDummy;⓪ ⓪ PROCEDURE setLenDummy (c: CARDINAL; env: ADDRESS);⓪ ⓪"END setLenDummy;⓪ ⓪ ⓪8(* proc.s for query *)⓪8(* ================ *)⓪ ⓪ PROCEDURE countEntry (REF path: ARRAY OF CHAR; env: ADDRESS): BOOLEAN;⓪ ⓪"BEGIN⓪$INC (env^); (* not clean, but saves a cast *)⓪$RETURN TRUE⓪"END countEntry;⓪"⓪ PROCEDURE deleteFile (REF path: ARRAY OF CHAR; env: ADDRESS): BOOLEAN;⓪ ⓪"VAR ioRes: INTEGER;⓪(stop : BOOLEAN;⓪ ⓪"BEGIN⓪$Delete (path, ioRes);⓪$doShowStatus (env, ioRes, stop);⓪$RETURN ~ stop⓪"END deleteFile;⓪"⓪ PROCEDURE deleteDir (REF path: ARRAY OF CHAR; env: ADDRESS): BOOLEAN;⓪ ⓪"VAR ioRes: INTEGER;⓪(stop : BOOLEAN;⓪"⓪"BEGIN⓪$DeleteDir (path, ioRes);⓪$doShowStatus (env, ioRes, stop);⓪$RETURN ~ stop⓪"END deleteDir;⓪ ⓪ ⓪ PROCEDURE fileInBuffer (REF path: ARRAY OF CHAR; env: ADDRESS): BOOLEAN;⓪ ⓪"VAR cb : copyBuffer;⓪(pos : LONGCARD;⓪ ⓪"BEGIN⓪$cb := copyBuffer (env);⓪$⓪$pos := 0L;⓪$REPEAT⓪&readIntoBuffer (path, pos, cb);⓪$UNTIL pos = 0L;⓪$⓪$RETURN cb^.success⓪"END fileInBuffer;⓪"⓪ PROCEDURE dirInBuffer (REF path: ARRAY OF CHAR; env: ADDRESS): BOOLEAN;⓪ ⓪"VAR cb : copyBuffer;⓪(bufElem: copyBufferElem;⓪(success: BOOLEAN;⓪(tPath : str128;⓪(⓪ ⓪"BEGIN⓪$cb := copyBuffer (env);⓪$⓪$createCopyBufferElem (cb, bufElem);⓪$IF ~ cb^.success THEN RETURN FALSE END;⓪$WITH bufElem^ DO⓪&Concat (cb^.newPath,⓪.FuncStrings.DelStr (path, 0, cb^.oldPathLen), tPath, success);⓪&IF ~ success THEN⓪(reportPathFault;⓪(deleteCopyBufferElem (cb, bufElem);⓪(RETURN FALSE⓪&END;⓪&FastStrings.Assign (tPath, newPath);⓪&⓪&isSubdir := TRUE;⓪&⓪$END;⓪$⓪$shrinkBufferElem (cb, bufElem, 0L);⓪$⓪$RETURN TRUE⓪"END dirInBuffer;⓪ ⓪ PROCEDURE setOldPathLen (len: CARDINAL; env: ADDRESS);⓪ ⓪"VAR cb: copyBuffer;⓪ ⓪"BEGIN⓪$cb := copyBuffer (env);⓪$⓪$cb^.oldPathLen := len;⓪"END setOldPathLen;⓪"⓪"⓪8(* Die exportierten Routinen *)⓪8(* ========================= *)⓪"⓪ PROCEDURE CountFilesAndDirs (REF path: ARRAY OF CHAR;⓪Al : List;⓪=VAR no : CARDINAL);⓪ ⓪"BEGIN⓪$no := 0;⓪$queryFileList (path, l, countEntry, countEntry, setLenDummy, ADR (no),⓪3TRUE);⓪"END CountFilesAndDirs;⓪"⓪ PROCEDURE DeleteFiles (REF path : ARRAY OF CHAR;⓪7files : List;⓪7noFiles : CARDINAL;⓪7showStatus : FileOpStatusProc;⓪7fileErrAlert: FileErrorAlertProc);⓪ ⓪"VAR status: statusRecord;⓪(stop : BOOLEAN;⓪ ⓪"BEGIN⓪$showStatus (noFiles, stop); IF stop THEN RETURN END;⓪&⓪$status.fileErrAlert := fileErrAlert;⓪$status.showStatus := showStatus;⓪$status.noFiles := noFiles;⓪$⓪$queryFileList (path, files, deleteFile, deleteDir, setLenDummy,⓪3ADR (status), FALSE);⓪"END DeleteFiles;⓪ ⓪ PROCEDURE CopyFiles (REF path : ARRAY OF CHAR;⓪5files : List;⓪5noFiles : CARDINAL;⓪5REF newPath : ARRAY OF CHAR;⓪5deleteOld,⓪5useAllMem : BOOLEAN;⓪5feAlert : FileExistsAlertProc;⓪5showStatus : FileOpStatusProc;⓪5fileErrAlert: FileErrorAlertProc);⓪ ⓪"VAR buffer : copyBuffer;⓪(len : CARDINAL;⓪(success,⓪(stop : BOOLEAN;⓪(entry : pcPtr;⓪ ⓪"BEGIN⓪$showStatus (noFiles, stop); IF stop THEN RETURN END;⓪&⓪$(* %% added 27.6.90 DS *)⓪$CreateList (pcList, success);⓪$IF success (* TRUE means error, but i don't wanted another var *)⓪$THEN reportOutOfMemory; RETURN END;⓪$⓪$createCopyBuffer (buffer, useAllMem, success);⓪$IF ~ success THEN reportOutOfMemory; RETURN END;⓪$buffer^.feAlert := feAlert;⓪$Assign (newPath, buffer^.newPath, success);⓪$len := Length (newPath);⓪$IF ~ success OR (len < 2) THEN⓪&reportPathFault;⓪&deleteCopyBuffer (buffer);⓪&RETURN⓪$END;⓪$IF newPath[len - 1] # '\' THEN Append ('\', buffer^.newPath, voidO) END;⓪$buffer^.status.fileErrAlert := fileErrAlert;⓪$buffer^.status.showStatus := showStatus;⓪$buffer^.status.noFiles := noFiles;⓪$buffer^.success := TRUE;⓪$⓪$queryFileList (path, files, fileInBuffer, dirInBuffer, setOldPathLen,⓪3buffer, TRUE);⓪$flushCopyBuffer (buffer);⓪$⓪$deleteCopyBuffer (buffer);⓪$⓪$(* %% added 27.6.90 DS *)⓪$(* delete pathList *)⓪$ResetList (pcList);⓪$entry := PrevEntry (pcList);⓪$WHILE entry # NIL DO⓪&RemoveEntry (pcList, voidO);⓪&DEALLOCATE (entry, 0L);⓪&entry := CurrentEntry (pcList);⓪$END;⓪$DeleteList (pcList, success)⓪$⓪"END CopyFiles;⓪"⓪ PROCEDURE FileInformation (REF name : ARRAY OF CHAR;⓪;showFileInfo: FileInfoProc;⓪;fileErrorAlt: FileErrorAlertProc);⓪ ⓪"VAR entry,⓪(oldEntry: DirEntry;⓪(ioRes : INTEGER;⓪(path,⓪(newName : str128;⓪(f: File;⓪(success : BOOLEAN;⓪ ⓪"PROCEDURE error (): BOOLEAN;⓪$BEGIN⓪&IF ioRes < fOK THEN fileErrorAlt (ioRes); RETURN TRUE END;⓪&RETURN FALSE⓪$END error;⓪ ⓪"PROCEDURE errorF (): BOOLEAN;⓪$BEGIN⓪&ioRes:= State (f);⓪&RETURN error ()⓪$END errorF;⓪ ⓪"BEGIN⓪$GetDirEntry (name, entry, ioRes);⓪$IF error () THEN RETURN END;⓪$oldEntry := entry;⓪$⓪$showFileInfo (entry);⓪$⓪$SplitPath (name, path, voidFN);⓪$Concat (path, entry.name, newName, success);⓪$IF ~ success THEN reportPathFault; RETURN END;⓪$⓪$IF ~ StrEqual (entry.name, oldEntry.name) THEN⓪&Rename (name, newName, ioRes);⓪&IF error () THEN RETURN END;⓪$END;⓪$IF NOT (subdirAttr IN oldEntry.attr) THEN⓪&IF ~VarEqual (entry.date, oldEntry.date)⓪&OR ~VarEqual (entry.time, oldEntry.time) THEN⓪(Open (f, newName, readOnly);⓪(IF errorF () THEN RETURN END;⓪(SetDateTime (f, entry.date, entry.time);⓪(IF errorF () THEN RETURN END;⓪(Close (f);⓪(IF errorF () THEN RETURN END;⓪&END;⓪&IF (entry.attr # oldEntry.attr) THEN⓪(SetFileAttr (newName, entry.attr, ioRes);⓪(IF error () THEN RETURN END;⓪&END;⓪$END;⓪"END FileInformation;⓪ ⓪ PROCEDURE FormatDisk ( drive : FormatDrive;⓪:sides,⓪:tracks,⓪:sectorsPerTrack,⓪:interleave : CARDINAL;⓪:REF name : ARRAY OF CHAR;⓪:showStatus : FileOpStatusProc;⓪6VAR result : FormatResult);⓪ ⓪"CONST fmtBufferSize = 11L * 1024L;⓪ ⓪"VAR fmtBuffer : ADDRESS;⓪"⓪"PROCEDURE write(* (noSectors, side, track, sector: CARDINAL) on the A7 *);⓪3⓪$(*$L-*)⓪$BEGIN⓪&ASSEMBLER⓪(MOVE.L (A7)+,(A3)+ ; save ret. addr.⓪(⓪(MOVE.W drive(A6),-(A7)⓪(CLR.L -(A7) ; not used⓪(MOVE.L fmtBuffer(A6),-(A7)⓪(MOVE.W #flopwr,-(A7) ; write the boot sector⓪(TRAP #xbios⓪(LEA $14(A7),A7⓪(⓪(MOVE.L -(A3),-(A7) ; restore ret. addr.⓪&END;⓪$END write;⓪$(*$L=*)⓪ ⓪"BEGIN⓪$ASSEMBLER⓪(MOVEM.L D4-D6,-(A7)⓪(⓪(SUBQ.W #1,drive(A6) ; 'drvA' ist 1⓪(⓪(MOVE.L result(A6),A0⓪(MOVE.W #failedFR,(A0) ; be pessimistic⓪#⓪(; format media⓪(;⓪(; D6.W ~ counts tracks | D4.W ~ counts sides⓪(⓪(LEA fmtBuffer(A6),A0⓪(MOVE.L A0,(A3)+⓪(MOVE.L #fmtBufferSize,(A3)+⓪(JSR ALLOCATE ; alloc. 'fmtBuffer'⓪(TST.L fmtBuffer(A6)⓪(BNE allocOk⓪(⓪(TRAP #noErrorTrap ; not enough memory avaible⓪(DC.W OutOfMemory - $4000⓪(BRA.W ende⓪ allocOk⓪(⓪(MOVE.W tracks(A6),D6⓪(SUBQ.W #1,D6⓪ trackLoop⓪ ⓪(MOVE.W sides(A6),D4⓪(SUBQ.W #1,D4⓪ sideLoop⓪ ⓪(MOVE.W #$E5E5,-(A7) ; virgin word⓪(MOVE.L #$87654321,-(A7) ; magic⓪(MOVE.W interleave(A6),-(A7)⓪(MOVE.W D4,-(A7)⓪(MOVE.W D6,-(A7)⓪(MOVE.W sectorsPerTrack(A6),-(A7)⓪(MOVE.W drive(A6),-(A7)⓪(CLR.L -(A7) ; not used⓪(MOVE.L fmtBuffer(A6),-(A7)⓪(MOVE.W #flopfmt,-(A7)⓪(TRAP #xbios ; format one track⓪(LEA $1A(A7),A7⓪(TST.W D0⓪(BNE.W stop ; bad sectors (no marking yet)⓪ ⓪(DBF D4,sideLoop⓪(⓪(MOVE.W D6,(A3)+⓪(SUBQ.W #2,A7⓪(MOVE.L A7,(A3)+⓪(MOVE.L showStatus(A6),A0⓪(JSR (A0)⓪(TST.W (A7)+⓪(BNE.W stop ; check user break⓪ ⓪(DBF D6, trackLoop⓪(⓪(; write boot sector⓪(⓪(MOVE.L fmtBuffer(A6),A0⓪(MOVE.W #127,D0⓪ clr1Loop⓪(CLR.L (A0)+⓪(DBF D0,clr1Loop⓪(⓪(CLR.W -(A7) ; not executable⓪(MOVEQ #1,D0⓪(ADD.W sides(A6),D0 ; 2 ~ SS, 3 ~ DS⓪(MOVE.W D0,-(A7)⓪(MOVE.L #$1000000,-(A7) ; random serial no.⓪(MOVE.L fmtBuffer(A6),-(A7)⓪(MOVE.W #protobt,-(A7) ; make a boot sector⓪(TRAP #xbios⓪(LEA $E(A7),A7⓪(⓪(MOVE.W #1,-(A7) ; one sector⓪(CLR.W -(A7) ; side 1⓪(CLR.W -(A7) ; track 0⓪(MOVE.W #1,-(A7) ; sector 1⓪(BSR write ; write boot sector⓪(TST.W D0⓪(BNE.W stop ; stop, if write err⓪(⓪(; write FATs⓪(⓪(MOVE.L fmtBuffer(A6),A0⓪(MOVE.W #895,D0 ; clear 7 sectors⓪ clr2Loop⓪(CLR.L (A0)+⓪(DBF D0,clr2Loop⓪(MOVE.L fmtBuffer(A6),A0⓪(MOVE.L #$F7FFFF00,(A0) ; FAT-start must be $F7 FF FF⓪(⓪(MOVE.W #5,-(A7) ; 5 sectors⓪(CLR.W -(A7) ; side 1⓪(CLR.W -(A7) ; track 0⓪(MOVE.W #2,-(A7) ; sector 2⓪(BSR write ; write FAT 1⓪(TST.W D0⓪(BNE.W stop ; stop, if write err⓪(⓪(MOVEQ #5,D6 ; 5 sectors⓪(MOVE.W sectorsPerTrack(A6),D4⓪(SUBQ.W #6,D4 ; 'sectorsPerTrack' - alreadyUsed -> D4⓪(SUB.W D4,D6 ; remaining sectors -> D6⓪(⓪(MOVE.W D4,-(A7) ; x sectors⓪(CLR.W -(A7) ; side 1⓪(CLR.W -(A7) ; track 0⓪(MOVE.W #7,-(A7) ; sector 7⓪(BSR write ; write FAT 2 Part 1⓪(TST.W D0⓪(BNE stop ; stop, if write err⓪(⓪(MOVE.W sides(A6),D0 ; if two sides then⓪(MOVEQ #1,D5 ; side 2, track 0⓪(SUB.W D5,D0 ; else⓪(SUB.W D0,D5 ; side 1, track 1⓪(EXG.L D0,D4 ; D4 = side, D5 = track⓪(⓪(TST.W D6⓪(BEQ noPart2 ; jump, if no sectors left⓪(⓪(MOVE.W D6,-(A7)⓪(MOVE.W D4,-(A7)⓪(MOVE.W D5,-(A7)⓪(MOVE.W #1,-(A7) ; sector 1⓪(MOVE.W drive(A6),-(A7)⓪(CLR.L -(A7) ; not used⓪(MULU #512,D0⓪(ADD.L fmtBuffer(A6),D0⓪(MOVE.L D0,-(A7) ; alreadyWrittenSecs * 512 + 'fmtBuffer'⓪(MOVE.W #flopwr,-(A7) ; write the boot sector⓪(TRAP #xbios⓪(LEA $14(A7),A7⓪(TST.W D0⓪(BNE stop ; stop, if write err⓪(⓪ noPart2⓪ ⓪(; write root directory⓪(⓪(MOVE.L fmtBuffer(A6),A0⓪(MOVE.L name(A6),A1 ; ADR (name) -> A1⓪(MOVE.W name+4(A6),D1 ; HIGH (name) -> D1⓪(MOVEQ #11,D0⓪(⓪(BRA nameStart⓪ nameLoop⓪(MOVE.B D2,(A0)+⓪(SUBQ.W #1,D1⓪(BMI nameSpaces⓪ nameStart⓪(MOVE.B (A1)+,D2⓪(DBEQ D0,nameLoop⓪(BNE nameOk⓪(⓪ nameSpaces⓪(BRA nameSpcStart⓪ nameSpcLoop⓪(MOVE.B #' ',(A0)+⓪ nameSpcStart⓪(DBF D0,nameSpcLoop⓪(⓪ nameOk⓪(MOVE.B #08,(A0)+ ; attribute set for volume label⓪(⓪(MOVE.W #7,-(A7) ; directory length = 7 sectors⓪(MOVE.W D4,-(A7)⓪(MOVE.W D5,-(A7)⓪(ADDQ.W #1,D6⓪(MOVE.W D6,-(A7)⓪(BSR write ; write directory⓪(TST.W D0⓪(BNE stop ; stop, if write err⓪(⓪(MOVE.L result(A6),A0⓪(MOVE.W #okFR,(A0) ; flag success!⓪(⓪ stop⓪(LEA fmtBuffer(A6),A0⓪(MOVE.L A0,(A3)+⓪(CLR.L (A3)+⓪(JSR DEALLOCATE ; dealloc. 'fmtBuffer'⓪ ende⓪(MOVEM.L (A7)+,D4-D6⓪$END;⓪"END FormatDisk;⓪"⓪ END FileManagement.⓪ ə
- (* $FFEA89F2$FFF57E96$FFF57E96$FFF57E96$FFF57E96$FFF57E96$FFF57E96$FFF57E96$FFF57E96$FFF57E96$FFF57E96$FFF57E96$FFF57E96$FFF57E96$FFF57E96$00006B12$FFF57E96$FFF57E96$FFF57E96$FFF57E96$FFF57E96$FFF57E96$FFF57E96$FFF57E96$FFF57E96$FFF57E96$FFF57E96$FFF57E96$FFF57E96$FFF57E96$FFF57E96$FFF57E96$FFF57E96$FFF57E96$FFF57E96$FFF57E96$FFF57E96$FFF57E96$FFF57E96$FFF57E96$FFF57E96$FFF57E96Ç$00000A48T.......T.......T.......T.......T.......T.......T.......T.......T.......T.......$00000933$0000093E$0000094B$00000168$0000094B$000009B7$00006A40$00007088$000071F9$000071CE$00000933$00000A4B$000009C2$000009D2$00000A48$00006E6D¶Çâ*)
-